package treex

type ITreeNode interface {
	AddChild(val *TreeNode)
}

type TreeNode struct {
	// 编号
	Id string

	/**
	 * 父节点
	 */
	Parent interface{}

	/**
	 * 标题
	 */
	Title string
	/**
	 * 图标
	 */
	Icon string

	/**
	 * 自定义数据
	 */
	Data interface{}

	/**
	 * 子节点
	 */
	Children []*TreeNode
}

func (n *TreeNode) AddChild(val *TreeNode) {
	n.Children = append(n.Children, val)
	val.Parent = n
}

func (n *TreeNode) GetChildById(id string) *TreeNode {
	if len(n.Children) == 0 {
		return nil
	}
	for i := 0; i < len(n.Children); i++ {
		child := n.Children[i]
		if child.Id == id {
			return child
		}
	}
	return nil
}

func (n *TreeNode) CreateChildId(child string) string {
	if n.Id == "/" {
		return "/" + child
	}
	return n.Id + "/" + child
}

/**
 * 如果返回true则继续
 * @param f
 */
func (n *TreeNode) Walk(f func(node *TreeNode) bool) {
	n._walk(f)
}

func (n *TreeNode) _walk(f func(node *TreeNode) bool) bool {
	if !f(n) {
		return false
	}
	if len(n.Children) > 0 {
		for i := 0; i < len(n.Children); i++ {
			child := n.Children[i]
			if !child._walk(f) {
				return false
			}
		}
	}

	return true
}

/**
 */
func (n *TreeNode) FindById(id string) *TreeNode {
	return n._findOne(func(node *TreeNode) bool {
		return node.Id == id
	})
}

/**
 * 如果返回true则继续
 * @param f
 */
func (n *TreeNode) FindOne(f func(node *TreeNode) bool) *TreeNode {
	return n._findOne(f)
}

func (n *TreeNode) _findOne(f func(node *TreeNode) bool) *TreeNode {
	if f(n) {
		return n
	}

	for i := 0; i < len(n.Children); i++ {
		child := n.Children[i]
		r := child._findOne(f)
		if r != nil {
			return r
		}
	}

	return nil
}

/**
 * 如果返回true则继续
 * @param f
 */
func (n *TreeNode) Find(f func(node *TreeNode) bool) []*TreeNode {
	return n._find(f)
}

func (n *TreeNode) _find(f func(node *TreeNode) bool) (r []*TreeNode) {
	if f(n) {
		r = append(r, n)
	}
	for i := 0; i < len(n.Children); i++ {
		child := n.Children[i]
		result := child._find(f)
		if len(result) > 0 {
			r = append(r, result...)
		}
	}

	return r
}

func (n *TreeNode) ToRoot() *TreeRoot {
	root := NewTreeRoot()
	root.Children = n.Children
	return root
}

func NewTreeRoot() (obj *TreeRoot) {
	obj = &TreeRoot{}
	obj.Id = "/"
	return
}

type TreeRoot struct {
	TreeNode
}
